#include "game_asset.h"
#include "game.h"
#include "game_opengl.h"
#if 0

#pragma pack(push, 1)  // 保存当前打包对齐方式，并设置新的打包对齐方式为 1 字节
struct bitmap_header {
    uint16 FileType;  // 文件类型标识符；通常是 'BM'（0x4D42），表示有效的 BMP 文件
    uint32 FileSize;  // BMP 文件的总大小（以字节为单位），包括文件头、信息头和位图数据
    uint16 Reserved1;  // 保留字段；未使用，必须为零
    uint16 Reserved2;  // 保留字段；未使用，必须为零
    uint32 BitmapOffset;  // 文件起始位置到位图数据（像素数据）的偏移量（以字节为单位）
    uint32 Size;  // 信息头的大小；对于 BITMAPINFOHEADER 通常为 40 字节
    int32 Width;  // 图像的宽度（以像素为单位）
    int32 Height;  // 图像的高度（以像素为单位）；正值表示从底到顶，负值表示从顶到底
    uint16 Planes;        // 颜色平面数；必须为 1（历史遗留字段）
    uint16 BitsPerPixel;  // 每像素的位数；常见值有 1（单色）、4（16 色）、8（256 色）、24（真彩色）
    uint32 Compression;   // 压缩类型；例如：
                          // 0 表示不压缩（BI_RGB）
                          // 1 表示 RLE-8 压缩（BI_RLE8）
                          // 2 表示 RLE-4 压缩（BI_RLE4）
                          // 3 表示使用位域（BI_BITFIELDS）
                          // 其他值可能表示自定义或不常见的压缩格式
    uint32 SizeOfBitmap;
    // 图像数据的大小（以字节为单位）；包括所有像素数据的总大小
    // 如果 Compression 为 0（未压缩），可以计算为 (宽度 × 高度 × 每像素字节数)
    int32 HorzResolution;  // 水平分辨率（像素/米）；表示图像的水平打印密度
    int32 VertResolution;  // 垂直分辨率（像素/米）；表示图像的垂直打印密度
    uint32 ColorUser;
    // 使用的颜色数；通常与调色板相关：
    // 0 表示使用默认的颜色数（与位深度匹配的最大颜色数）
    uint32 ColorsImportant;
    // 重要的颜色数；0 表示所有颜色都是重要的
    // 可以用于优化图像加载或显示，仅使用重要颜色

    // 以下字段仅在 Compression 为 3（BI_BITFIELDS）时有效
    uint32 RedMask;    // 用于提取红色分量的位掩码
                       // 指定存储红色通道的位的位置
    uint32 GreenMask;  // 用于提取绿色分量的位掩码
                       // 指定存储绿色通道的位的位置
    uint32 BlueMask;   // 用于提取蓝色分量的位掩码
                       // 指定存储蓝色通道的位的位置
};

struct WAVE_Header {
    uint32 RIFFID;
    uint32 Size;
    uint32 WAVEID;
};

#define RIFF_CODE(a, b, c, d) \
    (((uint32)(a) << 0) | ((uint32)(b) << 8) | ((uint32)(c) << 16) | ((uint32)(d) << 24))
enum {
    WAVE_ChunkID_fmt = RIFF_CODE('f', 'm', 't', ' '),
    WAVE_ChunkID_data = RIFF_CODE('d', 'a', 't', 'a'),
    WAVE_ChunkID_RIFF = RIFF_CODE('R', 'I', 'F', 'F'),
    WAVE_ChunkID_WAVE = RIFF_CODE('W', 'A', 'V', 'E'),
};
struct WAVE_chunk {
    uint32 ID;
    uint32 Size;
};
struct WAVE_fmt {
    uint16 wFormatTag;
    uint16 nChannels;
    uint32 nSamplesPerSec;
    uint32 nAvgBytesPerSec;
    uint16 nBlockAlign;
    uint16 wBitsPerSample;
    uint16 cbSize;
    uint16 wValidBitsPerSample;
    uint32 dwChannelMask;
    uint8 SubFormat[16];
};
#pragma pack(pop)


inline v2 TopDownAlign(loaded_bitmap *Bitmap, v2 Align) {
    // 根据位图的高度调整对齐的 Y 分量
    // 高度减去 1 确保 Y 值被正确翻转，适应自上而下的对齐方式
    Align.y = (real32)(Bitmap->Height - 1) - Align.y;
    Align.x = SafeRatio0(Align.x, (real32)Bitmap->Width);
    Align.y = SafeRatio0(Align.y, (real32)Bitmap->Height);
    return Align;
}

struct bit_scan_result {
    bool32 Found;
    uint32 Index;
};

// BitScanForward 函数查找给定值中第一个为 1 的位的位置
internal bit_scan_result BitScanForward(uint32 Value) {
    bit_scan_result Result = {};  // 变量，表示是否找到了 1 位，默认值为 false

#if COMPILER_MSVC
    Result.Found = _BitScanForward((unsigned long *)&Result.Index, Value);
#endif

    // 遍历 Value 的每一位（共 32 位）
    for (uint32 Test = 0; Test < 32; ++Test) {
        // 检查当前位是否为 1
        if (Value & (1 << Test)) {
            Result.Index = Test;  // 如果当前位是 1，将位的位置（Test）赋给 Index
            Result.Found = true;  // 标记找到了 1 位
            break;                // 找到后退出循环
        }
    }
    // 如果找到了 1 位，返回 true；否则返回 false
    return Result;
}

internal loaded_bitmap DebugLoadBMP(const char *FileName, v2 AlignPercentage = {0.5f, 0.5f}) {
    loaded_bitmap Result = {};
    // 注意：内存中的字节顺序是 AA BB GG RR，从底部到顶部
    // 在小端->0xRRGGBBAA

    // 调用 ReadEntireFile 函数以读取指定文件的整个内容
    debug_read_file_result ReadResult = DEBUGReadEntireFile(FileName);
    // 如果文件成功读取
    if (ReadResult.ContentsSize) {
        // 将文件内容强制转换为 bitmap_header 类型，以访问文件头信息
        bitmap_header *Header = (bitmap_header *)ReadResult.Contents;
        // 计算位图数据起始位置
        // 从文件内容中计算图像像素数据的开始位置
        Result.Memory = (uint32 *)((uint8 *)ReadResult.Contents + Header->BitmapOffset);
        Result.Width = Header->Width;
        Result.Height = Header->Height;
        Result.AlignPrecentage = AlignPercentage;
        Result.WidthOverHeight = SafeRatio0((real32)Result.Width, (real32)Result.Height);
        real32 PixelsToMeters = 1.0f / 42.0f;
        Result.NativeHeight = PixelsToMeters * Result.Height;
        // 定义一个指向像素数据的指针
        Assert(Result.Height >= 0);
#if 1
        uint32 *SourceDest = (uint32 *)Result.Memory;
        // 注意：如果你出于某种原因以通用方式使用这个，请记住 BMP 文件
        // 可以有两种方向，并且对于自上而下的图像，高度会是负数。

        int32 RedMask = Header->RedMask;                      // 获取红色通道掩码
        int32 GreenMask = Header->GreenMask;                  // 获取绿色通道掩码
        int32 BlueMask = Header->BlueMask;                    // 获取蓝色通道掩码
        int32 AlphaMask = ~(RedMask | GreenMask | BlueMask);  // 计算 alpha 通道掩码

        // 初始化每个颜色通道的位移量为 0，后续通过 BitScanForward 找到每个颜色的实际位移
        bit_scan_result RedScan = {};    // 红色通道的位移
        bit_scan_result GreenScan = {};  // 绿色通道的位移
        bit_scan_result BlueScan = {};   // 蓝色通道的位移
        bit_scan_result AlphaScan = {};  // Alpha 通道的位移

        // 调用 BitScanForward 查找红色通道的第一个 1 位，并记录该位的位置
        RedScan = BitScanForward(RedMask);

        // 调用 BitScanForward 查找绿色通道的第一个 1 位，并记录该位的位置
        GreenScan = BitScanForward(GreenMask);

        // 调用 BitScanForward 查找蓝色通道的第一个 1 位，并记录该位的位置
        BlueScan = BitScanForward(BlueMask);

        // 调用 BitScanForward 查找 alpha 通道的第一个 1 位，并记录该位的位置
        AlphaScan = BitScanForward(AlphaMask);

        Assert(RedScan.Found);
        Assert(GreenScan.Found);
        Assert(BlueScan.Found);
        Assert(AlphaScan.Found);
        // RedShiftDown 获取红色分量的位移量，通过 RedScan.Index 计算。
        int32 RedShiftDown = (int32)RedScan.Index;

        // GreenShiftDown 获取绿色分量的位移量，通过 GreenScan.Index 计算。
        int32 GreenShiftDown = (int32)GreenScan.Index;

        // BlueShiftDown 获取蓝色分量的位移量，通过 BlueScan.Index 计算。
        int32 BlueShiftDown = (int32)BlueScan.Index;

        // AlphaShiftDown 获取透明度分量的位移量，通过 AlphaScan.Index 计算。
        int32 AlphaShiftDown = (int32)AlphaScan.Index;

        // 遍历图像的每一行（高度）
        for (int32 Y = 0; Y < Header->Width; ++Y) {
            // 遍历图像的每一列（宽度）
            for (int32 X = 0; X < Header->Height; ++X) {
                // 对每个像素执行字节顺序调整操作
                // 通过位移操作将字节从右移到左，调整颜色通道的顺序。
                // *SourceDest >> 8: 将源像素右移8位，把前面的RGB通道一起往后移动八位
                // *SourceDest << 24: 将源像素低八位左移24位，到最前面
                uint32 C = *SourceDest;
#if 0
*SourceDest = ((((C >> AlphaShift.Index) & 0xFF) << 24) |  //
(((C >> RedShift.Index) & 0xFF) << 16) |    //
(((C >> GreenShift.Index) & 0xFF) << 8) |   //
(((C >> BlueShift.Index) & 0xFF) << 0));
#else
                v4 Texel = {
                    // 通过按位与操作和红色掩码提取红色分量，并右移至最低有效位。
                    // R = (C & RedMask) 提取红色分量，>> RedShiftDown 将其右移至合适的位置。
                    real32((C & RedMask) >> RedShiftDown),

                    // 通过按位与操作和绿色掩码提取绿色分量，并右移至最低有效位。
                    // G = (C & GreenMask) 提取绿色分量，>> GreenShiftDown 将其右移至合适的位置。
                    real32((C & GreenMask) >> GreenShiftDown),

                    // 通过按位与操作和蓝色掩码提取蓝色分量，并右移至最低有效位。
                    // B = (C & BlueMask) 提取蓝色分量，>> BlueShiftDown 将其右移至合适的位置。
                    real32((C & BlueMask) >> BlueShiftDown),

                    // 通过按位与操作和透明度掩码提取透明度分量，并右移至最低有效位。
                    // A = (C & AlphaMask) 提取透明度分量，>> AlphaShiftDown 将其右移至合适的位置。
                    real32((C & AlphaMask) >> AlphaShiftDown)};
                Texel = SRGB255ToLinear1(Texel);
#if 1
                Texel.rgb *= Texel.a;
#endif
                Texel = Linear1ToSRGB255(Texel);

                // 将各个颜色分量分别左移至相应的位置，并通过按位或操作组合成最终的颜色值。
                // 使用左移操作将每个分量移到正确的位位置，然后按位或操作合并所有分量。
                *SourceDest = (((uint32)(Texel.a + 0.5f) << 24) |  // 将红色分量移至高16位
                               ((uint32)(Texel.r + 0.5f) << 16) |  // 将绿色分量移至中间8位
                               ((uint32)(Texel.g + 0.5f) << 8) |   // 将蓝色分量移至低8位
                               ((uint32)(Texel.b + 0.5f) << 0));  // 将透明度分量移至高24位

#endif
#if 0
// 提取当前像素的颜色分量
uint32 C0 = *SourceDest & 0x000000FF;  // 提取Alpha通道的值
uint32 C1 = *SourceDest & 0x0000FF00;  // 提取Blue通道的值
uint32 C2 = *SourceDest & 0x00FF0000;  // 提取Green通道的值
uint32 C3 = *SourceDest & 0xFF000000;  // 提取Red通道的值

// 重新排列颜色通道顺序
// Alpha通道（C0）移动到最高位（左移24位）
// Red通道（C3）移动到次高位（左移16位）
// Green通道（C2）移动到次低位（左移8位）
// Blue通道（C1）移动到最低位（右移0位）
*SourceDest = (C0 << 24) | (C3 >> 8) | (C2 >> 8) | (C1 >> 8);
#endif
                // 移动指针到下一个像素
                ++SourceDest;
            }
        }

#endif
    }
    Result.Pitch = Result.Width * BITMAP_BYTES_PER_PIEXLE;
#if 0
Result.Memory = (uint8 *)Result.Memory + Result.Pitch * (Result.Height - 1);
Result.Pitch = - Result.Pitch;
#endif
    // 如果文件没有成功读取，则返回 NULL
    return Result;
}
#endif
#if 0
struct load_bitmap_work {
    game_assets *Assets;
    bitmap_id ID;
    task_with_memory *Task;
    loaded_bitmap *BitMap;

    asset_state FinalState;
};
#endif

internal loaded_bitmap DebugLoadBMP(const char *FileName, v2 AlignPercentage = {0.5f, 0.5f}) {
    Assert(!"NOOOOOOOOOOOOOO");
    (void)FileName;
    (void)AlignPercentage;
    loaded_bitmap Result = {};
    return (Result);
}

enum finalize_asset_operation {
    //
    FinalizeAsset_None,
    FinalizeAsset_Font,
    FinalizeAsset_Bitmap
};

struct load_asset_work {
    task_with_memory *Task;
    asset *Asset;

    platform_file_handle *Handle;
    uint64 Offset;
    uint64 Size;
    void *Destination;

    uint32 FinalState;
    finalize_asset_operation FinalizeOperation;
    platform_texture_op_queue *TextureOpQueue;
};

void AddOp(platform_texture_op_queue *Queue, texture_op *Source) {
    BeginTicketMutex(&Queue->Mutex);
    Assert(Queue->FirstFree);
    texture_op *Dest = Queue->FirstFree;
    Queue->FirstFree = Dest->Next;
    *Dest = *Source;
    Assert(Dest->Next == 0);
    Dest->Next = 0;
    if (Queue->Last) {
        Queue->Last = Queue->Last->Next = Dest;
    } else {
        Queue->First = Queue->Last = Dest;
    }
    EndTicketMutex(&Queue->Mutex);
}

internal void LoadAssetWorkDirectly(load_asset_work *Work) {
    TIMED_FUNCTION();
    Platform.ReadDataFromFile(Work->Handle, Work->Offset, Work->Size, Work->Destination);
    if (PlatformNoFileErrors(Work->Handle)) {
        switch (Work->FinalizeOperation) {
            case FinalizeAsset_None: {
            } break;
            case FinalizeAsset_Font: {
                loaded_font *Font = &Work->Asset->Header->Font;
                hha_font *HHA = &Work->Asset->HHA.Font;
                for (uint32 GlyphIndex = 0; GlyphIndex < HHA->GlyphCount; ++GlyphIndex) {
                    hha_font_glyph *Glyph = Font->Glyphs + GlyphIndex;
                    Assert(Glyph->UnicodeCodePoint < HHA->OnePastHeighestCodePoint);
                    Assert((uint32)(uint16)GlyphIndex == GlyphIndex);
                    Font->UnicodeMap[Glyph->UnicodeCodePoint] = (uint16)GlyphIndex;
                }
            } break;
            case FinalizeAsset_Bitmap: {
                loaded_bitmap *Bitmap = &Work->Asset->Header->Bitmap;
                texture_op Op = {};
                Op.IsAllocate = true;
                Op.Allocate.Width = Bitmap->Width;
                Op.Allocate.Height = Bitmap->Height;
                Op.Allocate.Data = Bitmap->Memory;
                Op.Allocate.ResultHandle = &Bitmap->TextureHandle;
                AddOp(Work->TextureOpQueue, &Op);
            } break;
            default: {
            } break;
        }
    }
    CompletePreviousWriteBeforeFutureWrites;

    if (!PlatformNoFileErrors(Work->Handle)) {
        ZeroSize(Work->Size, Work->Destination);
    }
    Work->Asset->State = Work->FinalState;
}

internal PLATFORM_WORK_QUEUE_CALLBACK(LoadAssetWork) {
    (void)Queue;
    load_asset_work *Work = (load_asset_work *)Data;
    LoadAssetWorkDirectly(Work);
    EndTaskWithMemory(Work->Task);
}

inline asset_file *GetFile(game_assets *Assets, uint32 FileIndex) {
    Assert(FileIndex < Assets->FileCount);
    asset_file *Result = Assets->Files + FileIndex;
    return Result;
}

inline platform_file_handle *GetFileHandleFor(game_assets *Assets, uint32 FileIndex) {
    Assert(FileIndex < Assets->FileCount);
    platform_file_handle *Handle = &GetFile(Assets, FileIndex)->Handle;
    return Handle;
}

internal asset_memory_block *FindBlockForSize(game_assets *Assets, memory_index Size) {
    asset_memory_block *Result = 0;
    for (asset_memory_block *Block = Assets->MemorySentinel.Next; Block != &Assets->MemorySentinel;
         Block = Block->Next) {
        if (!(Block->Flags & AssetMemory_Used)) {
            if (Block->Size >= Size) {
                Result = Block;
                break;
            }
        }
    }
    return Result;
}
internal void RemoveAssetHeaderFromList(asset_memory_header *Header);

internal bool32 MergeIfPossible(game_assets *Assets, asset_memory_block *First,
                                asset_memory_block *Second) {
    bool32 Result = false;
    if ((First != &Assets->MemorySentinel) && (Second != &Assets->MemorySentinel)) {
        if (!(First->Flags & AssetMemory_Used) && !(Second->Flags & AssetMemory_Used)) {
            uint8 *ExpectedSecond = (uint8 *)First + sizeof(asset_memory_block) + First->Size;
            if ((uint8 *)Second == ExpectedSecond) {
                Second->Next->Prev = Second->Prev;
                Second->Prev->Next = Second->Next;
                First->Size += sizeof(asset_memory_block) + Second->Size;
                Result = true;
            }
        }
    }
    return Result;
}

internal bool32 GenerationHasCompleted(game_assets *Assets, uint32 CheckID) {
    bool32 Result = true;
    for (uint32 Index = 0; Index < Assets->InFlightGenerationCount; ++Index) {
        if (Assets->InFlightGenerations[Index] == CheckID) {
            Result = false;
            break;
        }
    }
    return Result;
}

inline asset_memory_header *AcquireAssetMemory(game_assets *Assets, uint32 Size, uint32 AssetIndex,
                                               asset_header_type AssetType) {
    TIMED_FUNCTION();
    asset_memory_header *Result = 0;
    BeginAssetLock(Assets);
    asset_memory_block *Block = FindBlockForSize(Assets, Size);

    for (;;) {
        if (Block && (Size <= Block->Size)) {
            Block->Flags |= AssetMemory_Used;
            Result = (asset_memory_header *)(Block + 1);
            memory_index RemainingSize = Block->Size - Size;
            memory_index BlockSplitThreshold = 4096;
            if (RemainingSize > BlockSplitThreshold) {
                Block->Size -= RemainingSize;
                InsertBlock(Block, RemainingSize, (uint8 *)Result + Size);
            }
            break;
        } else {
            for (asset_memory_header *Header = Assets->LoadedAssetSentinel.Prev;
                 Header != &Assets->LoadedAssetSentinel; Header = Header->Prev) {
                asset *Asset = Assets->Assets + Header->AssetIndex;
                if ((Asset->State >= AssetState_Loaded) &&
                    (GenerationHasCompleted(Assets, Asset->Header->GenerationID))) {
                    Assert(Asset->State == AssetState_Loaded);
                    RemoveAssetHeaderFromList(Header);
                    if (Asset->Header->AssetType == AssetType_Bitmap) {
                        texture_op Op = {};
                        Op.IsAllocate = false;
                        Op.Deallocate.Handle = Asset->Header->Bitmap.TextureHandle;
                        AddOp(Assets->TextureOpQueue, &Op);
                    }
                    Block = (asset_memory_block *)Asset->Header - 1;
                    Block->Flags &= ~AssetMemory_Used;
                    if (MergeIfPossible(Assets, Block->Prev, Block)) {
                        Block = Block->Prev;
                    }
                    MergeIfPossible(Assets, Block, Block->Next);
                    Asset->Header = 0;
                    Asset->State = AssetState_Unloaded;

                    break;
                }
            }
        }
    }
    if (Result) {
        Result->AssetType = AssetType;
        Result->AssetIndex = AssetIndex;
        Result->TotalSize = Size;
        InsertAssetHeaderAtFront(Assets, Result);
    }
    EndAssetLock(Assets);
    return Result;
}

struct asset_memory_size {
    uint32 Total;
    uint32 Data;
    uint32 Section;
};

void LoadBitmap(game_assets *Assets, bitmap_id ID, bool32 Immediate) {
    TIMED_FUNCTION();
    asset *Asset = Assets->Assets + ID.Value;
    if (ID.Value) {
        if (AtomicCompareExchangeUInt32((volatile uint32 *)&(Asset->State),
                                        (uint32)AssetState_Queued, (uint32)AssetState_Unloaded) ==
            (uint32)AssetState_Unloaded) {
            task_with_memory *Task = 0;
            if (!Immediate) {
                Task = BeginTaskWithMemory(Assets->TranState, false);
            }
            if (Immediate || Task) {
                Asset = Assets->Assets + ID.Value;
                hha_bitmap *Info = &Asset->HHA.Bitmap;

                uint16 Width = SafeTruncateUInt16(Info->Dim[0]);
                uint16 Height = SafeTruncateUInt16(Info->Dim[1]);
                asset_memory_size Size = {};

                Size.Section = 4 * Width;
                Size.Data = Height * Size.Section;
                Size.Total = Size.Data + sizeof(asset_memory_header);

                Asset->Header = AcquireAssetMemory(Assets, Size.Total, ID.Value, AssetType_Bitmap);
                loaded_bitmap *Bitmap = &Asset->Header->Bitmap;
                Bitmap->AlignPrecentage = {Info->AlignPercentage[0], Info->AlignPercentage[1]};
                Bitmap->WidthOverHeight = (real32)Info->Dim[0] / (real32)Info->Dim[1];
                Bitmap->Width = SafeTruncateUInt16(Info->Dim[0]);
                Bitmap->Height = SafeTruncateUInt16(Info->Dim[1]);
                Bitmap->TextureHandle = 0;
                Bitmap->Pitch = SafeTruncateInt16(Size.Section);

                Bitmap->Memory = Asset->Header + 1;
                // PushSize(&Assets->AssetArena, MemorySize);
                load_asset_work Work{};
                Work.Task = Task;
                Work.Asset = Assets->Assets + ID.Value;
                Work.Handle = GetFileHandleFor(Assets, Asset->FileIndex);
                Work.Offset = Asset->HHA.DataOffset;
                Work.Size = Size.Data;
                Work.Destination = Bitmap->Memory;
                Work.FinalState = (AssetState_Loaded);
                Work.FinalizeOperation = FinalizeAsset_Bitmap;
                Work.TextureOpQueue = Assets->TextureOpQueue;

                if (Task) {
                    load_asset_work *TaskWork =
                        PushStruct(&Task->Arena, load_asset_work, NoClear());
                    *TaskWork = Work;
                    Platform.AddEntry(Assets->TranState->LowPriorityQueue, LoadAssetWork, TaskWork);
                } else {
                    LoadAssetWorkDirectly(&Work);
                }

            } else {
                Asset->State = AssetState_Unloaded;
            }
        } else if (Immediate) {
            asset_state volatile *State = (asset_state volatile *)&Asset->State;
            while (*State == AssetState_Queued) {
            }
        }
    }
}

void LoadFont(game_assets *Assets, font_id ID, bool32 Immediate) {
    TIMED_FUNCTION();
    asset *Asset = Assets->Assets + ID.Value;
    if (ID.Value) {
        if (AtomicCompareExchangeUInt32((volatile uint32 *)&(Asset->State),
                                        (uint32)AssetState_Queued, (uint32)AssetState_Unloaded) ==
            (uint32)AssetState_Unloaded) {
            task_with_memory *Task = 0;
            if (!Immediate) {
                Task = BeginTaskWithMemory(Assets->TranState, false);
            }
            if (Immediate || Task) {
                Asset = Assets->Assets + ID.Value;
                hha_font *Info = &Asset->HHA.Font;
                uint32 HorizontalAdvanceSize = sizeof(real32) * Info->GlyphCount * Info->GlyphCount;
                uint32 GlyphsSize = Info->GlyphCount * sizeof(hha_font_glyph);
                uint32 UnicodeMapSize = sizeof(uint16) * Info->OnePastHeighestCodePoint;
                uint32 SizeData = GlyphsSize + HorizontalAdvanceSize;
                uint32 SizeTotal = SizeData + sizeof(asset_memory_header) + UnicodeMapSize;

                Asset->Header = AcquireAssetMemory(Assets, SizeTotal, ID.Value, AssetType_Font);
                loaded_font *Font = &Asset->Header->Font;
                Font->BitmapIDOffset = GetFile(Assets, Asset->FileIndex)->FontBitmapIDOffset;
                Font->Glyphs = (hha_font_glyph *)(Asset->Header + 1);
                Font->HorizontalAdvance = (real32 *)((uint8 *)Font->Glyphs + GlyphsSize);
                Font->UnicodeMap =
                    (uint16 *)((uint8 *)Font->HorizontalAdvance + HorizontalAdvanceSize);
                ZeroSize(UnicodeMapSize, Font->UnicodeMap);

                // PushSize(&Assets->AssetArena, MemorySize);
                load_asset_work Work{};
                Work.Task = Task;
                Work.Asset = Assets->Assets + ID.Value;
                Work.Handle = GetFileHandleFor(Assets, Asset->FileIndex);
                Work.Offset = Asset->HHA.DataOffset;
                Work.Size = SizeData;
                Work.Destination = Font->Glyphs;
                Work.FinalState = (AssetState_Loaded);
                Work.FinalizeOperation = FinalizeAsset_Font;

                if (Task) {
                    load_asset_work *TaskWork = PushStruct(&Task->Arena, load_asset_work);
                    *TaskWork = Work;
                    Platform.AddEntry(Assets->TranState->LowPriorityQueue, LoadAssetWork, TaskWork);
                } else {
                    LoadAssetWorkDirectly(&Work);
                }

            } else {
                Asset->State = AssetState_Unloaded;
            }
        } else if (Immediate) {
            asset_state volatile *State = (asset_state volatile *)&Asset->State;
            while (*State == AssetState_Queued) {
            }
        }
    }
}

struct riff_iterator {
    uint8 *At;
    uint8 *Stop;
};

inline riff_iterator ParseChunkAt(void *At, void *Stop) {
    riff_iterator Iter;
    Iter.At = (uint8 *)At;
    Iter.Stop = (uint8 *)Stop;
    return Iter;
}
#if 0
inline riff_iterator NextChunk(riff_iterator Iter) {
    WAVE_chunk *Chunk = (WAVE_chunk *)Iter.At;
    uint32 Size = (Chunk->Size + 1) & ~1;
    Iter.At += sizeof(WAVE_chunk) + Size;
    return Iter;
}

inline bool32 IsValid(riff_iterator Iter) {
    bool32 Result = Iter.At < Iter.Stop;
    return Result;
}

inline void *GetChunkData(riff_iterator Iter) {
    void *Result = Iter.At + sizeof(WAVE_chunk);
    return Result;
}

inline uint32 GetType(riff_iterator Iter) {
    WAVE_chunk *Chunk = (WAVE_chunk *)Iter.At;
    uint32 Result = Chunk->ID;
    return Result;
}

inline uint32 GetChunkDataSize(riff_iterator Iter) {
    WAVE_chunk *Chunk = (WAVE_chunk *)Iter.At;
    uint32 Result = Chunk->Size;
    return Result;
}

internal loaded_sound DebugLoadWAV(const char *FileName, uint32 SectionFirstSampleIndex,
                                   uint32 SectionSampleCount) {
    loaded_sound Result = {};
    uint32 SampleCount = {};
    debug_read_file_result ReadResult = DEBUGReadEntireFile(FileName);
    if (ReadResult.ContentsSize != 0) {
        WAVE_Header *Header = (WAVE_Header *)ReadResult.Contents;
        Assert(Header->RIFFID == WAVE_ChunkID_RIFF);
        Assert(Header->WAVEID == WAVE_ChunkID_WAVE);

        int16 *SampleData = 0;
        uint32 ChannelCount = 0;
        uint32 SampleDataSize = 0;
        for (riff_iterator Iter =
                 ParseChunkAt(Header + 1, (uint8 *)(Header + 1) + Header->Size - 4);
             IsValid(Iter); Iter = NextChunk(Iter)) {
            switch (GetType(Iter)) {
                case WAVE_ChunkID_fmt: {
                    WAVE_fmt *fmt = (WAVE_fmt *)GetChunkData(Iter);
                    Assert(fmt->wFormatTag == 1);  // 只支持PCM
                    Assert(fmt->nSamplesPerSec = 48000);
                    Assert(fmt->wBitsPerSample == 16);
                    Assert(fmt->nBlockAlign == (sizeof(uint16) * fmt->nChannels));
                    ChannelCount = fmt->nChannels;
                } break;
                case WAVE_ChunkID_data: {
                    SampleData = (int16 *)GetChunkData(Iter);
                    SampleDataSize = GetChunkDataSize(Iter);
                } break;
            }
        }
        Assert(ChannelCount && SampleData);
        Result.ChannelCount = ChannelCount;
        SampleCount = SampleDataSize / (ChannelCount * sizeof(int16));
        if (ChannelCount == 1) {
            Result.Samples[0] = SampleData;
            Result.Samples[1] = 0;
        } else if (ChannelCount == 2) {
            Result.Samples[0] = SampleData;
            Result.Samples[1] = SampleData + SampleCount;
#if 0
            for (uint32 SampleIndex = 0; SampleIndex < Result.SampleCount; ++SampleIndex) {
                SampleData[2 * SampleIndex + 0] = (uint16)SampleIndex;
                SampleData[2 * SampleIndex + 1] = (uint16)SampleIndex;
            }

#endif
            for (uint32 SampleIndex = 0; SampleIndex < SampleCount; ++SampleIndex) {
                uint16 Source = SampleData[2 * SampleIndex];
                SampleData[2 * SampleIndex] = SampleData[SampleIndex];
                SampleData[SampleIndex] = Source;
            }
        } else {
            Assert(!"Invalid channel count in WAV file!");
        }
    }
    Result.ChannelCount = 1;
    bool32 AtEnd = true;
    if (SectionSampleCount) {
        Assert((SectionFirstSampleIndex + SectionSampleCount) <= SampleCount);
        AtEnd = ((SectionFirstSampleIndex + SectionSampleCount) == SampleCount);
        SampleCount = SectionSampleCount;
        for (uint32 ChannelIndex = 0; ChannelIndex < Result.ChannelCount; ChannelIndex++) {
            Result.Samples[ChannelIndex] += SectionFirstSampleIndex;
        }
    }

    if (AtEnd) {
        for (uint32 ChannelIndex = 0; ChannelIndex < Result.ChannelCount; ChannelIndex++) {
            for (uint32 SampleIndex = SampleCount; SampleIndex < (SampleCount + 8); ++SampleIndex) {
                Result.Samples[ChannelIndex][SampleIndex] = 0;
            }
        }
    }
    Result.SampleCount = SampleCount;
    return Result;
}
#endif

internal loaded_sound DebugLoadWAV(const char *FileName, uint32 SectionFirstSampleIndex,
                                   uint32 SectionSampleCount) {
    Assert(!"NO NOO NO NON ONO");
    (void)FileName;
    (void)SectionSampleCount;
    (void)SectionFirstSampleIndex;
    loaded_sound Result = {};
    return (Result);
}
#if 0
struct load_sound_work {
    game_assets *Assets;
    sound_id ID;
    task_with_memory *Task;
    loaded_sound *Sound;
    asset_state FinalState;
};

struct 
internal PLATFORM_WORK_QUEUE_CALLBACK(LoadSoundWork) {
    (void)Queue;
    load_sound_work *Work = (load_sound_work *)Data;
    hha_asset *HHAAsset = &Work->Assets->Assets[Work->ID.Value];
    hha_sound *Info = &HHAAsset->Sound;
    Work->Sound->SampleCount = Info->SampleCount;
    Work->Sound->ChannelCount = Info->ChennelCount;
    Assert(Work->Sound->ChannelCount < ArrayCount(Work->Sound->Samples));
    uint64 SampleDataOffset = HHAAsset->DataOffset;
    for (uint32 ChannelIndex = 0; ChannelIndex < Work->Sound->ChannelCount; ChannelIndex++) {
        Work->Sound->Samples[ChannelIndex] =
            (int16 *)(Work->Assets->HHAContents + SampleDataOffset);
        SampleDataOffset += Work->Sound->SampleCount * sizeof(int16);
    }
    CompletePreviousWriteBeforeFutureWrites;
    Work->Assets->Assets[Work->ID.Value].Sound = Work->Sound;
    Work->Assets->Assets[Work->ID.Value].State = Work->FinalState;
    EndTaskWithMemory(Work->Task);
}
#endif

void LoadSound(game_assets *Assets, sound_id ID) {
    TIMED_FUNCTION();
    asset *Asset = Assets->Assets + ID.Value;
    if (ID.Value &&
        AtomicCompareExchangeUInt32((volatile uint32 *)&(Asset->State), (uint32)AssetState_Queued,
                                    (uint32)AssetState_Unloaded) == (uint32)AssetState_Unloaded) {
        task_with_memory *Task = BeginTaskWithMemory(Assets->TranState, false);
        if (Task) {
            Asset = Assets->Assets + ID.Value;
            hha_sound *Info = &Asset->HHA.Sound;
            asset_memory_size Size = {};
            Size.Section = Info->SampleCount * sizeof(int16);
            Size.Data = Info->ChennelCount * Size.Section;
            Size.Total = Size.Data + sizeof(asset_memory_header);

            Asset->Header = AcquireAssetMemory(Assets, Size.Total, ID.Value, AssetType_Sound);
            loaded_sound *Sound = &Asset->Header->Sound;
            Sound->SampleCount = Info->SampleCount;
            Sound->ChannelCount = Info->ChennelCount;

            uint32 ChannelSize = Size.Section;

            void *Memory = Asset->Header + 1;
            // PushSize(&Assets->AssetArena, MemorySize);

            int16 *SoundAt = (int16 *)Memory;
            for (uint32 ChannelIndex = 0; ChannelIndex < Sound->ChannelCount; ++ChannelIndex) {
                Sound->Samples[ChannelIndex] = SoundAt;
                SoundAt += ChannelSize;
            }

            load_asset_work *Work = PushStruct(&Task->Arena, load_asset_work);
            Work->Task = Task;
            Work->Asset = Assets->Assets + ID.Value;
            Work->Handle = GetFileHandleFor(Assets, Asset->FileIndex);
            Work->Offset = Asset->HHA.DataOffset;
            Work->Size = Size.Data;
            Work->Destination = Memory;
            Work->FinalState = AssetState_Loaded;
            Work->FinalizeOperation = FinalizeAsset_None;

            Platform.AddEntry(Assets->TranState->LowPriorityQueue, LoadAssetWork, Work);
        } else {
            Asset->State = AssetState_Unloaded;
        }
    }
}

void PrefetchBitmap(game_assets *Assets, bitmap_id ID) { LoadBitmap(Assets, ID, false); }
void PrefetchSound(game_assets *Assets, sound_id ID) { LoadSound(Assets, ID); }

inline uint32 GetFirstAssetFrom(game_assets *Assets, assets_type_id TypeId) {
    TIMED_FUNCTION();
    uint32 Result = {};
    asset_type *Type = Assets->AssetTypes + TypeId;
    if (Type->FirstAssetIndex != Type->OnePastLastAssetIndex) {
        Result = Type->FirstAssetIndex;
    }
    return Result;
}

bitmap_id GetFirstBitmapFrom(game_assets *Assets, assets_type_id TypeId) {
    bitmap_id Result = {GetFirstAssetFrom(Assets, TypeId)};
    return Result;
}

inline sound_id GetFirstSoundFrom(game_assets *Assets, assets_type_id TypeId) {
    sound_id Result = {GetFirstAssetFrom(Assets, TypeId)};
    return Result;
}
inline uint32 GetClampedCodePoint(hha_font *Info, uint32 CodePoint) {
    uint32 Result = 0;
    if (CodePoint < Info->GlyphCount) {
        Result = CodePoint;
    }
    return Result;
}

inline uint32 GetGlyphFromCodePoint(hha_font *Info, loaded_font *Font, uint32 CodePoint) {
    uint32 Result = 0;
    if (CodePoint < Info->OnePastHeighestCodePoint) {
        Result = Font->UnicodeMap[CodePoint];
        Assert(Result < Info->GlyphCount);
    }
    return Result;
}

real32 GetHorizontalAdvanceForPair(hha_font *Info, loaded_font *Font, uint32 DesiredPrevCodePoint,
                                   uint32 DesiredCodePoint) {
    uint32 PrevGlyph = GetGlyphFromCodePoint(Info, Font, DesiredPrevCodePoint);
    uint32 Glyph = GetGlyphFromCodePoint(Info, Font, DesiredCodePoint);
    real32 Result = Font->HorizontalAdvance[PrevGlyph * Info->GlyphCount + Glyph];
    return Result;
}
bitmap_id GetBestMatchBitmapFrom(game_assets *Assets, assets_type_id TypeID,
                                 asset_vector *MatchVector, asset_vector *WeightVector);
bitmap_id GetBitmapForGlyph(game_assets *Assets, hha_font *Info, loaded_font *Font,
                            uint32 DesiredCodePoint) {
    // 【desired】 a. 渴望的；想得到的
    (void)Assets;
    uint32 Glyph = GetGlyphFromCodePoint(Info, Font, DesiredCodePoint);
    bitmap_id Result = Font->Glyphs[Glyph].BitmapID;
    Result.Value += Font->BitmapIDOffset;
    return Result;
}
real32 GetLineAdvanceFor(hha_font *Info) {
    real32 Result = Info->AscenderHeight + Info->DescenderHeight + Info->ExternalLeading;
    return Result;
}

real32 GetStartingBaselineY(hha_font *Info) {
    real32 Result = Info->AscenderHeight;
    return Result;
}